const emptyFn = () => {};
const isObject = (o) => o !== null && typeof o === "object";
const isEmpty = (v) => {
  if (v === null || v === undefined || v === "") return true;
  if (Array.isArray(v) && v.length == 0) return true;
  if (isObject(v) && Object.keys(v).length == 0) return true;
  return false;
};
const not = (fn) => (...args) => !fn(...args);
const notEmpty = not(isEmpty);
const stringify = (obj) => {
  let items = [];
  for (let key in obj) {
    items.push(encodeURIComponent(key) + "=" + encodeURIComponent(obj[key]));
  }
  return items.join("&");
};

/**
 * request for ajax
 *
 * support Promise request().then()
 *
 * @param {string} url url
 * @param {object} options {
 *  method: ['GET' | "POST"] ,
 *  headers: {},
 *  params: {},
 *  data: {},
 *  success: fn,
 *  error: fn
 * }
 */
async function request(url, options = {}) {
  return new Promise((resolve, rejected) => {
    let { method = "GET", headers = {}, params = {}, data = {} } = options;

    let xhr = new XMLHttpRequest();
    // events
    xhr.onload = (e) => {
      if (xhr.getResponseHeader("Content-Type").includes("application/json")) {
        return resolve(JSON.parse(xhr.response));
      }
      resolve(xhr.response);
    };
    xhr.onerror = (e) => rejected(e);
    //
    if (notEmpty(params)) {
      url += "?" + stringify(params);
    }
    xhr.open(method, url, true);
    // set header
    Object.entries(headers).forEach((item) => {
      let [name, value] = item;
      xhr.setRequestHeader(name, value);
    });
    // data
    if (notEmpty(data)) {
      xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      xhr.send(stringify(data));
    } else {
      xhr.send();
    }
  });
}

const todoHtml = (todo) => {
  return `<div class="card" id="todo-${todo.id}">
      <div class="card-body">
        <h3 class="card-title text-primary">${todo.title} 
          <span class="badge badge-secondary float-right">${todo.priority}</span>
        </h3>
        <p class="card-text">${todo.description}</p>
        <p class="finishedAt">${todo.finishedAt}</p>
        <a class="card-link" onclick="deleteTodo(${todo.id})">delete</a>
        <a class="card-link" onclick="finishedTodo(${todo.id})">finish</a>
      </div>
    </div>`;
};

const refresh = (todo) => {
  todoPage.style.display = "block";
  let el = document.getElementById("todo");
  el.innerHTML = "";
  // foreach
  let html = [];
  todo.forEach((i) => {
    html.push(todoHtml(i));
  });
  el.innerHTML = html.join("");
};

$(document).ready(async () => {
  // 获取用户的待办列表
  request("/todo").then((data) => {
    let { success, query } = data;
    if (success) {
      todoPage.style.display = "block";
      refresh(query);
    } else {
      loginPage.style.display = "block";
    }
  });
});

function deleteTodo(id) {
  request(`/delete/todo/${id}`, {
    method: "DELETE",
  }).then((data) => {
    if (data.success) {
      let el = document.getElementById("todo");
      el.removeChild(document.getElementById("todo-" + id));
    }
  });
}

function showRegister() {
  loginPage.style.display = "none";
  registerPage.style.display = "block";
}

function register() {
  request("/register", {
    method: "POST",
    data: {
      username: username.value,
      password: password.value,
      nickname: nickname.value,
    },
  }).then((data) => {
    let { success, message } = data;
    if (success) {
      loginPage.style.display = "block";
      registerPage.style.display = "none";
    } else {
      alert(message);
    }
  });
}

function login() {
  request("/login", {
    method: "POST",
    data: {
      username: usernameL.value,
      password: passwordL.value,
    },
  }).then((data) => {
    let result = data;
    if (result.success) {
      loginPage.style.display = "none";
      request("/todo").then((data) => {
        let result = data;
        todoPage.style.display = "block";
        refresh(result.query);
      });
    } else {
      // alert(result.msg);
    }
  });
}

function addTodo() {
  request("/add/todo", {
    method: "POST",
    data: {
      title: title.value,
      description: description.value,
      priority: priority.value,
    },
  }).then((data) => {
    let { success, object } = data;
    if (success) {
      $("#todo").append(todoHtml(object));
    }
  });
}

function finishedTodo(tid) {
  request(`/finished/todo/${tid}`, {
    method: "PUT",
  }).then((data) => {
    let { success, object } = data;
    if (success) {
      let el = document.querySelector(`div#todo-${tid} p.finishedAt`);
      el.innerHTML = object.finishedAt;
    }
  });
}
